package com.atguigu.gmall.payment.controller;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayConfig;
import com.alipay.api.internal.util.AlipaySignature;
import com.atguigu.gmall.common.bean.ResponseVo;
import com.atguigu.gmall.common.exception.GmallException;
import com.atguigu.gmall.oms.entity.OrderEntity;
import com.atguigu.gmall.payment.config.AlipayTemplate;
import com.atguigu.gmall.payment.entity.PaymentInfoEntity;
import com.atguigu.gmall.payment.feign.GmallOmsClient;
import com.atguigu.gmall.payment.service.PaymentInfoService;
import com.atguigu.gmall.payment.vo.PayAsyncVo;
import com.atguigu.gmall.payment.vo.PayVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.gson.Gson;
import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@Controller
@RequestMapping("/")
public class PaymentController {
    @Autowired
    GmallOmsClient omsClient;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    AlipayTemplate alipayTemplate;
    @Autowired
    PaymentInfoService paymentInfoService;
    //4、异步接收支付宝传递用户支付信息的接口:post方式调用，参数请求参数方式传递   异步回调接口
    //http://ptytaxeekhdr.ngrok2.xiaomiqiu.cn/pay/success
    @ResponseBody
    @PostMapping("pay/success")
    public String paysuccess(HttpServletRequest request){
        PaymentInfoEntity paymentInfoEntity = null;
        try {
            Map<String,String> params = new HashMap<String,String>();
            Map<String,String[]> requestParams = request.getParameterMap();
            for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
                String name = (String) iter.next();
                String[] values = (String[]) requestParams.get(name);
                String valueStr = "";
                for (int i = 0; i < values.length; i++) {
                    valueStr = (i == values.length - 1) ? valueStr + values[i]
                            : valueStr + values[i] + ",";
                }
                //乱码解决，这段代码在出现乱码时使用
                valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
                params.put(name, valueStr);
            }

            System.out.println("回调支付信息 ： "+ params);
            boolean signVerified = AlipaySignature.rsaCheckV1(params,
                    alipayTemplate.getAlipay_public_key(), "utf-8", "RSA2"); //调用SDK验证签名
            System.out.println("验签状态：" + signVerified);
            if(!signVerified){
                //验签失败
                throw new GmallException("支付信息验证签名失败,请联系管理员解决");
            }
            String outTradeNo = params.get("out_trade_no");
            paymentInfoEntity = paymentInfoService.getOne(new LambdaQueryWrapper<PaymentInfoEntity>().eq(PaymentInfoEntity::getOutTradeNo
                    , outTradeNo));
            String buyerPayAmount = params.get("total_amount").toString();
            if(paymentInfoEntity==null||
                    new BigDecimal(buyerPayAmount).compareTo(new BigDecimal("0.01"))!=0){
                //支付失败
                throw new GmallException("回调验证参数失败");
            }
            //修改订单日志状态为已支付的状态
            paymentInfoEntity.setPaymentStatus(1);
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            paymentInfoEntity.setCallbackTime(simpleDateFormat.parse(params.get("notify_time")));
            paymentInfoEntity.setCallbackContent(new Gson().toJson(params));

            paymentInfoService.updateById(paymentInfoEntity);
            // 修改oms服务中的订单状态、更新库存(设置用户的积分优惠券过期、更新用户的积分)
            System.out.println("支付宝异步回调成功");
            rabbitTemplate.convertAndSend("order_exchange" , "order.pay.success"
                    ,paymentInfoEntity.getOutTradeNo());
            return "success";//异步回调处理成功给支付宝的回执
        } catch (Exception e) {
            e.printStackTrace();
            if(paymentInfoEntity!=null){
                paymentInfoEntity.setPaymentStatus(0);
                paymentInfoService.updateById(paymentInfoEntity);
            }
            return "fail";
        }
    }
    //3、用户支付成功后 浏览器默认访问的回调接口  returnUrl
    //http://ptytaxeekhdr.ngrok2.xiaomiqiu.cn /pay/ok
    @GetMapping("pay/ok")
    public String payok(HttpServletRequest request)  {// 参数：表示支付宝返回的用户支付结果的参数
        //1、验签：如果签名或数据被篡改抛出异常
        /*
        如果遇到  验签失败的问题：
                1、配置文件的公钥私钥配置错误
                2、回传的参数问题：如果遇到乱码
         */
//        Boolean flag = alipayTemplate.checkSignature(payAsyncVo);
        //获取支付宝GET过来反馈信息
        try {
            Map<String,String> params = new HashMap<String,String>();
            Map<String,String[]> requestParams = request.getParameterMap();
            for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
                String name = (String) iter.next();
                String[] values = (String[]) requestParams.get(name);
                String valueStr = "";
                for (int i = 0; i < values.length; i++) {
                    valueStr = (i == values.length - 1) ? valueStr + values[i]
                            : valueStr + values[i] + ",";
                }
                //乱码解决，这段代码在出现乱码时使用
                valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
                params.put(name, valueStr);
            }

            System.out.println("支付信息 ： "+ params);
            boolean signVerified = AlipaySignature.rsaCheckV1(params,
                    alipayTemplate.getAlipay_public_key(), "utf-8", "RSA2"); //调用SDK验证签名
            System.out.println("验签状态：" + signVerified);
            if(!signVerified){
                //验签失败
                throw new GmallException("支付信息验证签名失败,请联系管理员解决");
            }

//            PayAsyncVo payAsyncVo = new PayAsyncVo();
            // 将params中的参数获取设置给payAsyncVo
            //2、验证参数：订单是否存在、状态是否为待支付状态、支付金额和订单金额是否一致
            String outTradeNo = params.get("out_trade_no");
            PaymentInfoEntity entity = paymentInfoService.getOne(new LambdaQueryWrapper<PaymentInfoEntity>().eq(PaymentInfoEntity::getOutTradeNo,
                    outTradeNo));
            String buyerPayAmount = params.get("total_amount").toString();//用户实际支付的金额
//        payAsyncVo.getPassback_params()
            if(StringUtils.isEmpty(outTradeNo) ||
                    new BigDecimal("0.01").compareTo(new BigDecimal(buyerPayAmount))!=0||
                    entity==null){
                throw new GmallException("订单支付金额错误,请联系管理员解决");
            }
            //3、更新订单日志的状态为支付成功(临时修改：以异步回调通知为准)
            //支付信息 ： {charset=utf-8, out_trade_no=202205181410045741526807312114511874, method=alipay.trade.page.pay.return,
            // total_amount=0.01,
            // trade_no=2022051822001432271456662789, auth_app_id=2021001163617452,
            // version=1.0, app_id=2021001163617452, sign_type=RSA2, seller_id=2088831489324244,
            // timestamp=2022-05-18 14:10:58}
            entity.setPaymentType(1);
            entity.setPaymentStatus(1);
            entity.setTradeNo(params.get("trade_no"));
            if(paymentInfoService.updateById(entity)){
                //将页面需要的数据存到request域中: Model
                request.setAttribute("total_amount" ,entity.getTotalAmount());
                //4、转发到支付成功的页面
                return "paysuccess";
            }else{
                throw new GmallException("订单支付状态异常,请联系管理员解决");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new GmallException("订单支付状态异常,请联系管理员解决");
        }
    }
    //2、选择支付方式后 立即支付提交的 获取支付二维码接口
    @ResponseBody
    @GetMapping("alipay.html")
    public String alipay(@RequestParam("orderToken")String orderToken) throws UnsupportedEncodingException {
        //通过支付宝sdk的工具类  封装一个表单页面响应给浏览器
        // 表单的提交地址 是支付宝的二维码页面的获取地址 同时需要将订单的参数作为表单参数一起提交
        try {
            //1、查询最新的订单信息
            ResponseVo<OrderEntity> orderEntityResponseVo =
                    omsClient.queryOrderByOrderSn(orderToken);
            OrderEntity orderEntity = orderEntityResponseVo.getData();
            if(orderEntity==null ||
                    orderEntity.getStatus()!=0||
                    orderEntity.getPayAmount().compareTo(new BigDecimal(0))==0){
                //订单查询不到 或者 订单状态不是待支付 或者订单金额为0
                throw new GmallException("订单状态异常，请联系管理员解决");
            }
            //订单状态是待支付状态
            //2、可以将订单数据转为 待支付日志数据存入到数据库表中
            PaymentInfoEntity entity = new PaymentInfoEntity();
            entity.setOutTradeNo(orderToken);
            entity.setTotalAmount(orderEntity.getPayAmount());//用户应付金额
            entity.setCreateTime(new Date());
            entity.setPaymentStatus(0);
            entity.setSubject(URLEncoder.encode("尚硅谷商城订单数据","UTF-8"));//如果要使用中文，必须使用UrlEncoder处理
            entity.setPaymentType(1);
            paymentInfoService.save(entity);
            //3、封装支付宝生成二维码需要的参数 生成自动提交的表单
            PayVo payVo = new PayVo();
//            payVo.setTotal_amount(orderEntity.getPayAmount());
            payVo.setTotal_amount("0.01");// 支付金额
            payVo.setOut_trade_no(orderToken);//我们的订单唯一的表示
            //防止恶意攻击的唯一性的字段
            payVo.setPassback_params(entity.getId().toString());
            payVo.setSubject(entity.getSubject());//二维码用户扫描支付时的提示文本
            //pay方法返回的是一个表单页面数据，页面的最后js直接提交表单请求给表单的 action地址(支付宝的二维码页面地址)
            return alipayTemplate.pay(payVo);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            throw new GmallException("订单支付失败，请联系管理员解决");
        }

    }

    //1、跳转到支付方式选择页面
    //http://payment.gmall.com/pay.html?orderToken=202205180851504991526727226518515714
    @GetMapping("pay.html")
    public String pay(@RequestParam("orderToken")String orderToken, Model model){
                //根据orderToken查询 订单对象  存到request域中 orderEntity
        ResponseVo<OrderEntity> orderEntityResponseVo =
                omsClient.queryOrderByOrderSn(orderToken);
        OrderEntity orderEntity = orderEntityResponseVo.getData();
        if(orderEntity==null ||
            orderEntity.getStatus()!=0||
          orderEntity.getPayAmount().compareTo(new BigDecimal(0))==0){
            //订单查询不到 或者 订单状态不是待支付 或者订单金额为0
            throw new GmallException("订单状态异常，请联系管理员解决");
        }
        model.addAttribute("orderEntity" , orderEntity);
        return "pay";
    }
}
